package com.tianji.learning.utils;

import com.tianji.common.utils.JsonUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.DelayQueue;

@Data
@RequiredArgsConstructor
@Slf4j
@Component
public class LearningRecordDelayTaskHandler {
    private final StringRedisTemplate stringRedisTemplate;
    private final DelayQueue<DelayTask<RecordTaskData>> queue = new DelayQueue<>();
    private final static String RECORD_KEY_TEMPLATE = "learning:record:{}";
    private final LearningRecordMapper recordMapper;
    private final ILearningLessonService lessonService;
    private static volatile boolean begin = true;
    // volatile 保证可见性

    @PostConstruct
    public void init(){
        CompletableFuture.runAsync(this::handleDelayTask);
    }

    public void destroy(){
        begin = false;
        log.debug("延迟任务停止执行！");
    }

    public void handleDelayTask(){
        while (begin){
            try{
                // 获取到期的延时任务
                DelayTask<RecordTaskData> task = queue.take();
                RecordTaskData data = task.getData();
                log.info("data:{}",data);
                // 查询redis缓存
                LearningRecord learningRecord = readLearningRecordCache(data.getLessonId(), data.getSectionId());
                log.info("缓存数据:{}",learningRecord);
                if (learningRecord == null){
                    continue;
                }
                if (!learningRecord.getMoment().equals(data.getMoment())){
                    // 不一致，说明用户还在持续提交播放进度，放弃旧数据
                    continue;
                }

                // 4.一致，持久化播放进度数据到数据库
                // 4.1.更新学习记录的moment
                learningRecord.setFinished(null);
                recordMapper.updateById(learningRecord);
                // 4.2.更新课表最近学习信息
                LearningLesson learningLesson = new LearningLesson();
                learningLesson.setId(data.getLessonId());
                learningLesson.setLatestLearnTime(LocalDateTime.now());
                learningLesson.setLatestSectionId(data.getSectionId());
                lessonService.updateById(learningLesson);
            }catch (Exception e){
                log.error("处理延迟任务发生异常", e);
            }
        }
    }

    public void addLeaningRecordTask(LearningRecord learningRecord){
        // 添加数据到换成redis
        writeRecordCache(learningRecord);
        // 提交任务到延迟队列
        queue.add(new DelayTask<>(new RecordTaskData(learningRecord),Duration.ofSeconds(20)));

    }

    // 读取缓存
    public LearningRecord readLearningRecordCache(Long lessonId,Long sectionId){
        try {
            String key = StringUtils.format(RECORD_KEY_TEMPLATE,lessonId);
            Object cacheData = stringRedisTemplate.opsForHash().get(key, sectionId.toString());
            if (cacheData == null){
                return null;
            }
            return JsonUtils.toBean(cacheData.toString(),LearningRecord.class);
        } catch (Exception e) {
            log.error("数据读取错误",e);
            return null;
        }
    }

    // 删除缓存
    public void deleteLearningRecordCache(Long lessonId,Long sectionId){
        String key = StringUtils.format(RECORD_KEY_TEMPLATE,lessonId);
        stringRedisTemplate.opsForHash().delete(key,sectionId.toString());
    }

    public void writeRecordCache(LearningRecord learningRecord) {
        log.info("更新学习记录缓存");
        try {
            // 将要缓存的数据转成json格式
            String json = JsonUtils.toJsonStr(new RecordCacheData(learningRecord));
            String key = StringUtils.format(RECORD_KEY_TEMPLATE,learningRecord.getLessonId());
            stringRedisTemplate.opsForHash().put(key,learningRecord.getSectionId().toString(),json);
            // 设置过期时间
            stringRedisTemplate.expire(key, Duration.ofMinutes(1));
        } catch (Exception e) {
            log.error("更新学习记录缓存异常", e);
        }
    }

    @Data
    @NoArgsConstructor
    private static class RecordCacheData{
        private Long id;
        private Integer moment;
        private Boolean finished;

        public RecordCacheData(LearningRecord learningRecord) {
            this.id = learningRecord.getId();
            this.moment = learningRecord.getMoment();
            this.finished = learningRecord.getFinished();
        }
    }

    @Data
    @NoArgsConstructor
    private static class RecordTaskData{
        private Long lessonId;
        private Long sectionId;
        private Integer moment;

        public RecordTaskData(LearningRecord learningRecord) {
            this.lessonId = learningRecord.getLessonId();
            this.sectionId = learningRecord.getSectionId();
            this.moment = learningRecord.getMoment();
        }
    }

}
